﻿using UnityEngine;
using UnityEngine.UI;
using System.Collections;
using System.Collections.Generic;
using UnityEngine.Extension;
using System.Linq;
using System.Reflection;
using System.Reflection.Extension;
using System.Extension;
using System;

[Serializable]
public class MemberLink
{
    public string sourcePath, destChildPath, destMemberPath;
    public bool continousUpdate;
}

[Serializable]
public class ActionLink
{
    public string childPath, componentPath, methodPath;
}

[Serializable]
public class NavigationLink
{
    public string childPath, componentPath;
    public ControlBehaviour toScreen;
    public string conditionPath;
}

[Serializable]
public class Group
{
    public Transform contentPanel;
    public GameObject templateCell;
    public UnityEngine.Object dataSource;
    public string enumeratablePath, delegatePath;
    public List<MemberLink> links;
    public List<ActionLink> commandLinks;
    public List<NavigationLink> navigationLink;

    List<GameObject> cells;
    public List<LinkCatch> catchLinks { get { return m_catchLinks; } }
    List<LinkCatch> m_catchLinks = new List<LinkCatch>();

    public static List<LinkCatch> GenerateGroups(List<Group> groups, ControlBehaviour controlBehaviour)
    {
        List<LinkCatch> result = new List<LinkCatch>();
        groups.ForEach(g => {
            g.GenerateList(controlBehaviour);
            result.AddRange(g.catchLinks);
        });
        return result;
    }

    public static void ClearGroups(List<Group> groups)
    {
        groups.ForEach(g =>  g.Clear() );
    }

    public void Clear()
    {
        contentPanel.DestroyChilds(); //delete all child
        if(cells.isNotNull()) cells.Clear();
        if(catchLinks.isNotNull()) catchLinks.Clear();
    }

    public void GenerateList(ControlBehaviour controlBehaviour)
    {
        if (templateCell)    //only if template GameObject cell is avaliable
        {
            contentPanel.DestroyChilds(); //delete all child

            //templateCell.SetActive(false);
            object value = dataSource.GetValue(enumeratablePath);
            if (value.isNotNull())
            {
                //MemberInfo memberInfo = dataSource.GetChildMemberInfo(enumeratablePath);        // All problem goes here....
                //if (memberInfo.isPrimitive())
                //{
                //    string strValue = (string)value;
                //    //Debug.Log("EPath :" + enumeratablePath);
                //    if (strValue.isNotEmpty())
                //    {
                //        int count = int.Parse(strValue);
                //        //Debug.Log("Creating : " + count);
                //        CreateCells(count);
                //    }
                //}
                //else
                {
                    IEnumerable items = (IEnumerable)value;
                    if (Application.isPlaying && items != null)
                        CreateCells(items, controlBehaviour);
                }
            }
            //else
            //{
            //    value = dataSource.InvokeMethod(enumeratablePath);
            //    if(value.isNotNull() && Application.isPlaying)
            //        CreateCells(value, controlBehaviour);
            //}
        }
    }

  

    void CreateCells(int count)
    {
        cells = new List<GameObject>();
        for(int i = 0; i< count; i++)
        {
            GameObject cell = templateCell.InstantiateInHierarchy();
            cells.Add(cell);
        }
        cells.ForEach(c => c.SetActive(true));
    }

    void CreateCells(object items, ControlBehaviour controlBehaviour)
    {
        cells = new List<GameObject>();
        foreach (object item in items as IEnumerable)
        {
            GameObject cell = GameObject.Instantiate(templateCell) as GameObject;  //templateCell.InstantiateInHierarchy();
           // ControlBehaviour delegateref = GetDelegate();
            //if (delegateref.isNotNull())    //Deletate here to source
            //    delegateref.OnCellCreation(cell, item);
            if(cell.isNotNull())
            {
                PopulateCell(item, cell);
                LinkMethods(item, cell, controlBehaviour);
                cells.Add(cell);
                cell.transform.SetParent(contentPanel);
                cell.transform.localScale = Vector3.one;
            }
        }
                cells.ForEach(c => c.SetActive(true));
    }

    private ControlBehaviour GetDelegate()
    {
        ControlBehaviour result = null;
        if(dataSource is GameObject)
            result = (dataSource as GameObject).GetComponent<ControlBehaviour>();
        return result;
    }

    private void LinkMethods(object item, GameObject cell, ControlBehaviour controlBehaviour)
    {
        foreach (ActionLink cmdLink in commandLinks)
        {
            int index = 0;
            string[] components = cmdLink.componentPath.GetComponents();
            object comp = cell.GetComponent(cmdLink.childPath, components, ref index);
            if (comp is Button)
            {
                object[] parameters = { item };
                string methodPath = cmdLink.methodPath;
                Button button = comp as Button;
                button.onClick.AddListener(() => dataSource.InvokeMethod(methodPath, parameters));
            }
        }

        foreach (NavigationLink naviLink in navigationLink)
        {
            int index = 0;
            string[] components = naviLink.componentPath.GetComponents();
            object comp = cell.GetComponent(naviLink.childPath, components, ref index);
            if (comp is Button)
            {
                ControlBehaviour toScreen = naviLink.toScreen, currentScreen = controlBehaviour;
                Button button = comp as Button;
                string conditionalPath = naviLink.conditionPath;
                bool canNavigate = true;
                button.onClick.AddListener(() => {
                    if (conditionalPath.isNotEmpty())
                        canNavigate = (bool)dataSource.GetValue(conditionalPath);
                    //Debug.Log("Can : " + canNavigate);
                    if (canNavigate) currentScreen.NavigateTo(toScreen); 
                });
            }
        }
    }

    void PopulateCell(object source, GameObject cell)
    {
        links.ForEach(link =>
        {
            object sourceValue = source.GetValue(link.sourcePath);
            cell.SetValue(sourceValue, link.destMemberPath, link.destChildPath);

            if(link.continousUpdate)
                m_catchLinks.Add( new LinkCatch(source, cell, link));
        });
    }
}

/*
  bool isValidObject, isNonEnumeration;
  ControlBehaviour controlBehaviour;
  int noofItems, iteration;
  public void Initialize(ControlBehaviour controlBehaviour)
  {
      if(templateCell.isNotNull())
      {
          templateCell.SetActive(false);
          this.controlBehaviour = controlBehaviour;
          cells = new List<GameObject>();

          MemberInfo memberInfo = dataSource.GetChildMemberInfo(enumeratablePath);
          isNonEnumeration = memberInfo.isPrimitive();
          if (isNonEnumeration)
          {
              noofItems = (int)dataSource.GetValue(enumeratablePath);
          }
          else
          {
              IEnumerable items = (IEnumerable)dataSource.GetValue(enumeratablePath);
              foreach (var item in (items as IEnumerable))
                  noofItems++;
          }
          isValidObject = true;
      }
  }

  object GetItemAt(int index)
  {
      IEnumerable items = (IEnumerable)dataSource.GetValue(enumeratablePath);
      object result = null;
      foreach (var item in (items as IEnumerable))
          if(index-- == 0)
          {
              result = item;
              break;
          }
      return result;
  }

  public void Update()
  {
      if(isValidObject)
      {
          if(noofItems > iteration)
          {
              GameObject cell = templateCell.InstantiateInHierarchy();
              if (!isNonEnumeration)
              {
                  var item = GetItemAt(iteration);
                  ControlBehaviour delegateref = GetDelegate();
                  if (delegateref.isNotNull())
                      delegateref.OnCellCreation(cell, item);
                  //Deletate here to source

                  PopulateCell(item, cell);
                  LinkMethods(item, cell, controlBehaviour);
                  cells.Add(cell);

                  if (iteration == noofItems-1)
                      cells.ForEach(c => c.SetActive(true));
              }
          }
          iteration++;
          catchLinks.ForEach(catchLink => catchLink.Sync());
      }
  }
  */
